package com.sau.pixelcart.aspect;

import com.sau.pixelcart.common.context.UserContext;
import com.sau.pixelcart.common.exception.BusinessException;
import com.sau.pixelcart.domain.dto.ProductDTO;
import com.sau.pixelcart.domain.entity.InventoryAdjustment;
import com.sau.pixelcart.domain.entity.ProductInventory;
import com.sau.pixelcart.service.IInventoryAdjustmentService;
import com.sau.pixelcart.service.IProductInventoryService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Aspect
@Component
public class InventoryAspect {

    // 使用ThreadLocal保存原始库存信息（线程安全）
    private final ThreadLocal<Map<String, Integer>> originalStocks = new ThreadLocal<>();

    @Autowired
    private  IInventoryAdjustmentService inventoryAdjustmentService;

    @Autowired
    private IProductInventoryService productInventoryService;

    // 定义两个切点：入库和出库操作
    @Pointcut("execution(* com.sau.pixelcart.service.IProductInventoryService.saveList(..))")
    public void inStockOperation() {}

    @Pointcut("execution(* com.sau.pixelcart.service.IProductInventoryService.outStock(..))")
    public void outStockOperation() {}

    // 前置通知：记录原始库存
    @Before("inStockOperation() || outStockOperation()")
    public void recordOriginalStock(JoinPoint joinPoint) {
        List<ProductDTO> products = extractProducts(joinPoint.getArgs());
        if (!products.isEmpty()) {
            // 批量查询原始库存
            List<ProductInventory> productInventoryList = productInventoryService.list();
            Map<String, Integer> inventoryMap = productInventoryList.stream().collect(Collectors.toMap(ProductInventory::getProductId, ProductInventory::getStock));

            originalStocks.set(inventoryMap);
        }
    }

    // 入库后置通知
    @AfterReturning(pointcut = "inStockOperation()", returning = "result")
    public void afterInStock(JoinPoint joinPoint, Object result) {
        processStockChange(joinPoint, "inStock");
    }

    // 出库后置通知
    @AfterReturning(pointcut = "outStockOperation()", returning = "result")
    public void afterOutStock(JoinPoint joinPoint, Object result) {
        processStockChange(joinPoint, "outStock");
    }

    private void processStockChange(JoinPoint joinPoint, String operationType) {
        // 获取方法参数中的产品列表
        Object[] args = joinPoint.getArgs();
        if (args.length > 0 && args[0] instanceof List) {
            List<ProductDTO> products = (List<ProductDTO>) args[0];

            //查询当前库存
            Map<String, Integer> newInventoryMap = productInventoryService.list().stream().collect(Collectors.toMap(ProductInventory::getProductId, ProductInventory::getStock));

            // 异步处理日志记录
            List<InventoryAdjustment> inventoryAdjustmentList = products.stream().map(productDTO -> {
                InventoryAdjustment inventoryAdjustment = new InventoryAdjustment();
                inventoryAdjustment.setProductId(productDTO.getId());
                inventoryAdjustment.setOldStock(originalStocks.get().get(productDTO.getId()));inventoryAdjustment.setNewStock(newInventoryMap.get(productDTO.getId()));
                inventoryAdjustment.setReason(operationType);
                inventoryAdjustment.setOperatorId(UserContext.getUser());
                inventoryAdjustment.setAdjustmentTime(LocalDateTime.now());
                return inventoryAdjustment;
            }).collect(Collectors.toList());

            boolean b = inventoryAdjustmentService.saveBatch(inventoryAdjustmentList);
            if (!b) {
                throw new BusinessException("库存记录日志生成失败");
            }
        }
    }
    private List<ProductDTO> extractProducts(Object[] args) {
        if (args != null && args.length > 0 && args[0] instanceof List) {
            final List<?> rawList = (List<?>) args[0];
            return rawList.stream()
                    .filter(item -> item instanceof ProductDTO)
                    .map(item -> (ProductDTO) item)
                    .collect(Collectors.toList());
        }
        return Collections.emptyList();
    }
}
